<?php

require_once "plugin.abstract.php";


class Broker extends Plugin_Abstract
{
    private $_plugins;
    

    function Broker() {
        $this->_plugins = array();
    }

    /**
     * @param  Plugin_Abstract $plugin
     * @param  int $stackIndex
     * @return Broker
     */
    public function registerPlugin (Plugin_Abstract $plugin, $stackIndex = null) {
        if (false !== array_search($plugin, $this->_plugins, true)) {
            throw new JxException('Plugin already registered');
        }

        $stackIndex = (int) $stackIndex;

        if ($stackIndex) {
            if (isset($this->_plugins[$stackIndex])) {
                throw new JxException('Plugin with stackIndex "' . $stackIndex . '" already registered');
            }
            $this->_plugins[$stackIndex] = $plugin;
        } else {
            $stackIndex = count($this->_plugins);
            while (isset($this->_plugins[$stackIndex])) {
                ++$stackIndex;
            }
            $this->_plugins[$stackIndex] = $plugin;
        }

        $request = $this->request();
        if ($request) {
            $this->_plugins[$stackIndex]->setRequest($request);
        }
        $response = $this->response();
        if ($response) {
            $this->_plugins[$stackIndex]->setResponse($response);
        }

        ksort($this->_plugins);

        return $this;
    }

    /**
     * @param string|Plugin_Abstract $plugin Plugin object or class name
     * @return Broker
     */
    public function unregisterPlugin ($plugin) {
        if ($plugin instanceof Plugin_Abstract) {
            // Given a plugin object, find it in the array
            $key = array_search($plugin, $this->_plugins, true);
            if (false === $key) {
                throw new JxException('Plugin never registered.');
            }
            unset($this->_plugins[$key]);
        } elseif (is_string($plugin)) {
            // Given a plugin class, find all plugins of that class and unset them
            foreach ($this->_plugins as $key => $_plugin) {
                $type = get_class($_plugin);
                if ($plugin == $type) {
                    unset($this->_plugins[$key]);
                }
            }
        }
        return $this;
    }
    
    /**
     * @param  string $class
     * @return bool
     */
    public function hasPlugin ($class) {
        foreach ($this->_plugins as $plugin) {
            $type = get_class($plugin);
            if ($class == $type) {
                return true;
            }
        }

        return false;
    }
    /**
     * @param  string $class Class name of plugin(s) desired
     * @return false|Plugin_Abstract|array Returns false if none found, plugin if only one found, and array of plugins if multiple plugins of same class found
     */
    public function getPlugin ($class) {
        $found = array();
        foreach ($this->_plugins as $plugin) {
            $type = get_class($plugin);
            if ($class == $type) {
                $found[] = $plugin;
            }
        }

        switch (count($found)) {
            case 0:
                return false;
            case 1:
                return $found[0];
            default:
                return $found;
        }
    }

    /**
     * Retrieve all plugins
     *
     * @return array
     */
    public function getPlugins () {
        return $this->_plugins;
    }

    /**
     * Set request object, and register with each plugin
     *
     * @param Request $request
     * @return Broker
     */
    public function setRequest (Request $request) {
        $this->_request = $request;

        foreach ($this->_plugins as $plugin) {
            $plugin->setRequest($request);
        }

        return $this;
    }
    /**
     * Set response object
     *
     * @param Response $response
     * @return Broker
     */
    public function setResponse (Response $response) {
        $this->_response = $response;

        foreach ($this->_plugins as $plugin) {
            $plugin->setResponse($response);
        }

        return $this;
    }
    
 
    public function appendUrlFile ($fname) {
        $this->_dispatcher->appendFile($fname);
    }




    /**
     * @param Request $request
     */
    public function routeStartup () {
        foreach ($this->_plugins as $plugin) {
            try {
                $plugin->routeStartup();
            } catch (Exception $e) {
                $this->response()->appendException($e);
            }
        }
    }


    /**
     * @param  Request $request
     */
    public function routeShutdown () {
        foreach ($this->_plugins as $plugin) {
            try {
                $plugin->routeShutdown();
            } catch (Exception $e) {
                $this->response()->appendException($e);
            }
        }
    }


    /**
     * @param  Request $request
     */
    public function dispatchLoopStartup () {
        foreach ($this->_plugins as $plugin) {
            try {
                $plugin->dispatchLoopStartup();
            } catch (Exception $e) {
                $this->response()->appendException($e);
            }
        }
    }


    /**
     * @param  Request $request
     */
    public function preDispatch () {
        foreach ($this->_plugins as $plugin) {
            try {
                $plugin->preDispatch();
            } catch (Exception $e) {
                $this->response()->appendException($e);
            }
        }
    }


    /**
     * @param  Request $request
     * @return void
     */
    public function postDispatch () {
        foreach ($this->_plugins as $plugin) {
            try {
                $plugin->postDispatch();
            } catch (Exception $e) {
                $this->response()->appendException($e);
            }
        }
    }


    /**
     * @param  Request $request
     * @return void
     */
    public function dispatchLoopShutdown () {
       foreach ($this->_plugins as $plugin) {
           try {
                $plugin->dispatchLoopShutdown();
            } catch (Exception $e) {
                $this->response()->appendException($e);
            }
       }
    }


}

